/*
// Class: ImageUtils
// Usage: Collection of methods for processing images
// Author: Moritz Vieth
*/

#include <assert.h>
#include "ImageUtils.h"
#include "Output.h"




#include "ImageUtils.h"

//#include <assert.h>
#include <string>

#include <cxcore.h>
#include <cv.h>

#include "Pixel.h"
//#include "Blob.h"



ImageUtils::ImageUtils() {}

ImageUtils::~ImageUtils() {}








/**
 * Get the value of a pixel in an IplImage.
 * If the image has more than one channel, the values of the chennels will be
 * accumulated.
 * While this may seem odd at first, it is useful for quick checking if a pixel
 * is zero or not in an IplImage, regardless of the image being binary or not.
 * There are methods for accessing single channels of color images or retrieving
 * a Pixel object.
 * 
 * @param image The image to obtain the value from.
 * @param x The x coordinate of the pixel
 * @param y The y coordinate of the pixel
 * 
 * @return The sum of all channel values at the specified coordinates.
 **/
int ImageUtils::getPixelValue(IplImage *image, int x, int y) {
    int sum = 0;
    
    for (int chan = 0; chan < image->nChannels; chan++) {
        sum += getPixelValue(image, x, y, chan);
    }
    return sum;
}

/**
 * Get the value of a pixel in an IplImage.
 * If the image has more than one channel, the values of the chennels will be
 * accumulated.
 * While this may seem odd at first, it is useful for quick checking if a pixel
 * is zero or not in an IplImage, regardless of the image being binary or not.
 * There are methods for accessing single channels of color images or retrieving
 * a Pixel object.
 * 
 * @param image The image to obtain the value from.
 * @param point The coordinates of the pixel
 * 
 * @return The sum of all channel values at the specified coordinates.
 **/
int ImageUtils::getPixelValue(IplImage *image, CvPoint point) {

    return getPixelValue(image, point.x, point.y);
}


/**
 * Get the value of one channel a pixel in an IplImage.
 * This encapsulates the pointer arithmetic to access pixel values, as
 * proposed by OpenCV.
 * 
 * @param image The image to obtain the value from.
 * @param x The x coordinate of the pixel
 * @param y The y coordinate of the pixel
 * @param channel The desired channel
 * 
 * @return The channel value at the specified coordinates.
 **/
int ImageUtils::getPixelValue(IplImage *image, int x, int y, int channel) {
    assert(channel < image->nChannels);
    assert(x >= 0);
    assert(y >= 0);
    assert(x < image->width);
    assert(y < image->height);

    return (((uchar*)(image->imageData + image->widthStep*(y))))[(x * image->nChannels) + channel] ;
}

/**
 * Get the value of one channel a pixel in an IplImage.
 * This encapsulates the pointer arithmetic to access pixel values, as
 * proposed by OpenCV.
 * 
 * @param image The image to obtain the value from.
 * @param point The coordinates of the pixel
 * @param channel The desired channel
 * 
 * @return The channel value at the specified coordinates.
 **/
int ImageUtils::getPixelValue(IplImage *image, CvPoint point, int channel) {
    assert(channel < image->nChannels);

    return getPixelValue(image, point.x, point.y, channel);
}


/**
 * Get a Pixel object at a specified position in an IplImage.
 * All unused channels in the Pixel object will be set to 0.
 * 
 * @param image The image to obtain the Pixel from.
 * @param x The x coordinate of the pixel
 * @param y The y coordinate of the pixel
 * @param numChannels The number of channels of the Pixel
 * 
 * @return A Pixel object encapsualtion the information at the specified loxation.
 **/
Pixel ImageUtils::getPixel(IplImage *image, int x, int y, int numChannels) {
    assert(numChannels <= 4);
    assert(numChannels > 0);
    assert(y >= 0 && x >= 0);
    assert(y < image->height && x < image->width);


    int channelValues[4];
	channelValues[0] = 0;
	channelValues[1] = 0;
	channelValues[2] = 0;
	channelValues[3] = 0;
	
    for (int i = 0; i < numChannels; i++) {
        channelValues[i] = getPixelValue(image, x, y, i);
    }

    Pixel ret(x, y, channelValues[2], channelValues[1], channelValues[0], channelValues[3]);

    return  ret;


}

/**
 * Get a Pixel object at a specified position in an IplImage.
 * All unused channels in the Pixel object will be set to 0.
 * 
 * @param image The image to obtain the Pixel from.
 * @param point The coordinates of the pixel
 * @param numChannels The number of channels of the Pixel
 * 
 * @return A Pixel object encapsualtion the information at the specified loxation.
 **/
Pixel ImageUtils::getPixel(IplImage *image, CvPoint point, int numChannels) {
    return getPixel(image, point.x, point.y, numChannels);
}












/**
 * Set the value of one channel of a pixel in an IplImage.
 * This encapsualtes the pointer arithmetics needed to access pixels in IplImages,
 * as proposed by OpenCV.
 * The input is checked for image boundary violations. Trying to access a value
 * out-of-bounds will cause the application to abort.
 * 
 * @param image The image to change
 * @param x The X coordinate of the pixel
 * @param y The y coordinate of the pixel
 * @param channel The Channel to change
 * @param value The value to set
 **/
void ImageUtils::setPixelValue(IplImage* image, int x, int y, int channel, int value) {
    assert(channel >= 0);
    assert(channel < image->nChannels);
    assert(x >= 0);
    assert(y >= 0);
    assert(x < image->width);
    assert(y < image->height);
    (((uchar*)(image->imageData + image->widthStep*(y))))[x * image->nChannels + channel] = (uchar)value;
}


/**
 * Set the value of one channel of a pixel in an IplImage.
 * This encapsualtes the pointer arithmetics needed to access pixels in IplImages,
 * as proposed by OpenCV.
 * The input is checked for image boundary violations. Trying to access a value
 * out-of-bounds will cause the application to abort.
 * 
 * @param image The image to change
 * @param point The coordinates of the pixel to change
 * @param channel The Channel to change
 * @param value The value to set
 **/
void ImageUtils::setPixelValue(IplImage* image, CvPoint point, int channel, int value) {

    setPixelValue(image, point.x, point.y, channel, value);
}


/**
 * Set the value of one, three or four channels of a pixel in an IplImage.
 * This encapsualtes the pointer arithmetics needed to access pixels in IplImages,
 * as proposed by OpenCV.
 * The input is checked for image boundary violations. Trying to access a value
 * out-of-bounds will cause the application to abort.
 * 
 * @param image The image to change
 * @param x The X coordinate of the pixel
 * @param y The y coordinate of the pixel
 * @param num_channels The number of channels to set. Must be 1, 3 or 4.
 * @param value The values to set.
 * @param order The colo channel order of the values. Must be ORDER_BGR or ORDER_RGB.
 **/
void ImageUtils::setPixelValue(IplImage* image, int x, int y, int num_channels, int* value, int order) {
    assert(num_channels <= 4);
    assert(num_channels != 2);
    assert(num_channels > 0);
    assert(y >= 0 && x >= 0);
    assert(y < image->height && x < image->width);

    switch(num_channels) {
    case 1:
        setPixelValue(image, x, y, 0, value[0]);
        break;

    case 3:
        switch(order) {
        case ORDER_BGR:
            for (int chan = 0; chan < num_channels; chan++) {
                setPixelValue(image, x, y, chan, value[chan]);
            }
            break;

        case ORDER_RGB:
            for (int chan = 0; chan < num_channels; chan++) {
                setPixelValue(image, x, y, 2 - chan, value[chan]);
            }
            break;
        }
        break;

    case 4:
        switch(order) {
        case ORDER_BGR:
            for (int chan = 0; chan < 3; chan++) {
                setPixelValue(image, x, y, chan, value[chan]);
            }
            setPixelValue(image, x, y, 3, value[3]);
            break;


        case ORDER_RGB:
            for (int chan = 0; chan < 3; chan++) {
                setPixelValue(image, x, y, 2 - chan, value[chan]);
            }
            setPixelValue(image, x, y, 3, value[3]);
            break;
        }
        break;
    }


}


/**
 * Set the value of one, three or four channels of a pixel in an IplImage.
 * This encapsualtes the pointer arithmetics needed to access pixels in IplImages,
 * as proposed by OpenCV.
 * The input is checked for image boundary violations. Trying to access a value
 * out-of-bounds will cause the application to abort.
 * 
 * @param image The image to change
 * @param point The coordinates of the pixel 
 * @param num_channels The number of channels to set. Must be 1, 3 or 4.
 * @param value The values to set.
 * @param order The colo channel order of the values. Must be ORDER_BGR or ORDER_RGB.
 **/
void ImageUtils::setPixelValue(IplImage* image, CvPoint point, int num_channels, int* value, int order) {
    setPixelValue(image, point.x, point.y, num_channels, value, order);
}


/**
 * Set the value of a pixel in an IplImage.
 * 
 * @param image The image to change
 * @param pixel The pixel to set.
 **/
void ImageUtils::setPixel(IplImage* image, Pixel pixel) {

    //setPixelValue(image, pixel.x, pixel.y, image->nChannels, pixel.getRGB(), ORDER_RGB);
    for (int i = 0; i < image->nChannels; ++i){
    	switch(i){
    		case 0:
    			setPixelValue(image, pixel.x, pixel.y, 0, pixel.b);
    			break;
    		case 1:
    			setPixelValue(image, pixel.x, pixel.y, 1, pixel.g);
    			break;
    		case 2:
    			setPixelValue(image, pixel.x, pixel.y, 2, pixel.r);
    			break;
    		case 3:
    			setPixelValue(image, pixel.x, pixel.y, 3, pixel.alpha);
    			break;	
    		
    	}	
    }
    
    
}
















/**
 * Get the absolute difference of two colors, as a new color value.
 * Useful to determine if two colors are 'similar'.
 * 
 * @param colorA the first color to compare 
 * @param colorB the second color to compare
 * 
 * @return CvScalar enclosing the difference values of each color channel.
 **/ 
CvScalar ImageUtils::getColorDifference(CvScalar colorA, CvScalar colorB){
	
	return cvScalar(fabs(colorA.val[0] - colorB.val[0]),
					fabs(colorA.val[1] - colorB.val[1]),
					fabs(colorA.val[2] - colorB.val[2]),
					fabs(colorA.val[3] - colorB.val[3]));
}












/**
 * Draw a CvRect, either filled or not.
 * Convenience method, because OpenCV does not provide a method for drawing rectangles
 * by passing a CvRect. God knows why.
 * 
 * @param image The image to draw in
 * @param rect der CvRect to draw
 * @param color The color in which to draw
 * @param filled Specifies if the rectangle should be filled (duh!)
 **/
void ImageUtils::drawRect(IplImage* image, CvRect rect, CvScalar color, bool filled){
 	
	/* create points from CvRect */
	CvPoint topLeft = cvPoint(rect.x, rect.y);
 	CvPoint bottomRight = cvPoint (rect.x + rect.width, rect.y + rect.height);
 	
	/* ensure that the rect fits in the image boundaries */
 	//TODO isn't that done by OpenCV?

	topLeft.x     = (int)ImageUtils::fitRange(topLeft.x, 0, image->width);
 	topLeft.y     = (int)ImageUtils::fitRange(topLeft.y, 0, image->height);
 	bottomRight.x = (int)ImageUtils::fitRange(bottomRight.x, 0, image->width);
 	bottomRight.y = (int)ImageUtils::fitRange(bottomRight.y, 0, image->height);
 	
	if (filled){
		cvRectangle(image, topLeft, bottomRight, color, -1);
	} else {
		cvRectangle(image, topLeft, bottomRight, color, 1);
	}
 	
 }



/**
 * Draws a CvBox2D in an IplImage
 * 
 * @param image The image to draw in
 * @param box The box to draw
 * @param color The line color
 * @param filled Specifies wether the box should be filled
 **/
void ImageUtils::drawBox2D(IplImage* image, CvBox2D box, CvScalar color ,bool filled){
	if (filled){
		drawBox2DFilled(image, box, color);
	} else {
		drawBox2D(image, box, color);
	}
}


/**
 * Draws the outline of a CvBox2D in an IplImage.
 * 
 * @param image The image to draw in
 * @param box The box to draw
 * @param color The line color
 **/
void ImageUtils::drawBox2D(IplImage* image, CvBox2D box, CvScalar color){
	//TODO maybe use cvPolyLine
	
	CvPoint pt1, pt2, pt3, pt4;
    CvPoint2D32f boxPoints[4];

    cvBoxPoints(box, boxPoints);

    pt1 = cvPointFrom32f(boxPoints[0]);
    pt2 = cvPointFrom32f(boxPoints[1]);
    pt3 = cvPointFrom32f(boxPoints[2]);
    pt4 = cvPointFrom32f(boxPoints[3]);


    cvLine(image, pt1, pt2, color);
    cvLine(image, pt1, pt4, color);
    cvLine(image, pt2, pt3, color);
    cvLine(image, pt3, pt4, color);
  
} 

/**
 * Draws a filled CvBox2D in an image.
 *
 * @param image The image to draw in
 * @param box The box to draw
 * @param color The line color 
 **/
void ImageUtils::drawBox2DFilled(IplImage* image, CvBox2D box, CvScalar color){
	//TODO maybe use cvFillPoly

    IplImage* mask = getMaskFromCvBox2D(box, image->width, image->height);


	for(int x = 0; x < image->width; ++x){
		for(int y = 0; y < image->height; ++y){
			if(getPixelValue(mask, x, y) > 0){
				for (int chan = 0; chan < image->nChannels; ++chan){
					setPixelValue(image, x, y, chan, (int)(color.val[chan]));	
				}			
			}
		}
	}
	
} 


/**
 * Just a convenience wrapper for cvPolyLine, if only one polygon should be drawn.
 * cvPolyLine expects arrays, and you always have to dereference anything when calling it.
 * This method is to avoid that (which is just plain laziness, admittedly).
 * The lines will always be closed.
 * 
 * @param image the Image to draw in
 * @param points The coordinates of the polygon
 * @param nPoints The number of coordinates
 * @param color The color of the line
 * @param thickness The thickness of the line.
 **/
void ImageUtils::drawPolyLine(IplImage* image, CvPoint* points, int nPoints, CvScalar color, int thickness){
	cvPolyLine(image, &points, &nPoints, 1, 1, color, thickness);
}


/**
 * Draws an assymetric box (i.e. a quadrangel that is not neccessarily rectangular).
 * The four points should be sequential (e.g. top left, top right, bottom right, bottom left).
 * 
 * @param image The image to draw in
 * @param a The first corner
 * @param b The second corner
 * @param c The third corner
 * @param d The fourth corner
 * @param color The line color
 **/
void ImageUtils::drawAsymmetricBox(IplImage* image, CvPoint a, CvPoint b, CvPoint c, CvPoint d, CvScalar color){
	CvPoint* points = new CvPoint[4];
	points[0] = a;
	points[1] = b;
	points[2] = c;
	points[3] = d;
	
	ImageUtils::drawPolyLine(image, points, 4, color);
	
	delete points;
}



/**
 * Draw an arrow in an IplImage.
 * Used for visualisation.
 * Original code by David Stavens, Stanford.
 * http://robots.stanford.edu/cs223b05/notes/optical_flow_demo.cpp
 * 
 * @param image The image to draw the arrow in.
 * @param start The start of the arrow.
 * @param end The tip of the arrow.
 * @param color The color of the arrow.
 * @param thickness The thickness (in pixels) of the arrow line.
 * @param stretchFactor A factor by which to stretch an arrow;
 * 						useful if an arrow would otherwise be too small for visualization.
 **/
void ImageUtils::drawArrow(IplImage* image, CvPoint start, CvPoint end, CvScalar color, int thickness, int stretchFactor){
	/** 
	 * Original code by David Stavens, Stanford.
	 * http://robots.stanford.edu/cs223b05/notes/optical_flow_demo.cpp
	 **/
	
	double angle; 
	double hypotenuse;
	
	angle = atan2( (double) start.y - end.y, (double) start.x - end.x );
	hypotenuse = sqrt((double)((start.y - end.y)*(start.y - end.y) + (start.x - end.x)*(start.x - end.y)));
	
	/* Here we lengthen the arrow by the stretch factor */
	end.x = (int) (start.x - stretchFactor * hypotenuse * cos(angle));
	end.y = (int) (start.y - stretchFactor * hypotenuse * sin(angle));
	
	/* Draw the main line of the arrow. */
	cvLine( image, start, end, color, thickness, CV_AA, 0 );
	
	/* Now draw the tips of the arrow. Do some scaling so that the
	* tips look proportional to the main line of the arrow. */
	start.x = (int) (end.x + 9 * cos(angle + 3.14159 / 4));
	start.y = (int) (end.y + 9 * sin(angle + 3.14159 / 4));
	cvLine( image, start, end, color, thickness, CV_AA, 0 );
	
	start.x = (int) (end.x + 9 * cos(angle - 3.14159 / 4));
	start.y = (int) (end.y + 9 * sin(angle - 3.14159 / 4));
	cvLine( image, start, end, color, thickness, CV_AA, 0 );
	
}



/**
 * Put some text into an IplImage.
 * Convenience method to not always have to care about the font etc.
 * 
 * @param image The image in which to put the text
 * @param text Anything you ever wanted to say.
 * @param coordinates Where to put the text (bottom left corner)
 * @param color The color of the text
 * @param size The scaling of the text. 1.0 means normal size.
 * @param thickness The thickness of the letters
 **/ 
void ImageUtils::writeText(IplImage* image, std::string text, CvPoint coordinates, CvScalar color, double size, int thickness){
	
	assert(image != NULL);
	
	CvFont font;
	double shear = 0.0;
	
	cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, size, size, shear, thickness);
	
	cvPutText(image, text.c_str(), coordinates, &font, color);
}







/**
 * Test if two rectangles (e.g. bounding boxes) overlap or are
 * close to each other.
 * 
 * @param a The first rectangle
 * @param b The second rectangle
 * @param distance The distance the rectangles may have to still be considered overlapping.
 * 
 * @return True, if there is an overlap between the boxes
 */
bool ImageUtils::overlaps(CvRect a, CvRect b, int distance){
	
	/* create CvPoints to improve readability, and to save on
	 * corner calculations */
	CvPoint topLeft, bottomRight, otherTopLeft, otherBottomRight;
	
	topLeft = cvPoint(a.x, a.y);
	bottomRight = cvPoint(a.x + a.width, a.y + a.height);
	otherTopLeft = cvPoint(b.x, b.y);
	otherBottomRight = cvPoint(b.x + b.width, b.y + b.height);
	
	
	if ((    topLeft.x     >= otherTopLeft.x	 - distance	/// |-------| [other]
          && topLeft.x     <= otherBottomRight.x + distance	/// |       |
          && topLeft.y     >= otherTopLeft.y	 - distance	/// |    |--|-----| [this]
          && topLeft.y     <= otherBottomRight.y + distance	/// |    |  |     |
          													/// |----|--|     |
          													///      |        |
       )) {													///      |--------|
        return true;
    } else if ((   bottomRight.x >= otherTopLeft.x	   - distance ///       |--------| [other]
                && topLeft.x	 <= otherTopLeft.x	   + distance ///       |        |
                && topLeft.y     >= otherTopLeft.y	   - distance /// |-----|-- - - -| -
                && topLeft.y     <= otherBottomRight.y + distance /// |     |        |
                												  /// |     |--------|
                												  ///
              )) {												  /// | [this]
        return true;
    } else if ((   												  /// |--------| [this]
                												  /// |        |
                   bottomRight.x >= otherTopLeft.x	   - distance /// |     |--|-----|
                && bottomRight.x <= otherBottomRight.x + distance /// |     |  |     |
                && bottomRight.y >= otherTopLeft.y	   - distance /// |-----|--|     |
                && bottomRight.y <= otherBottomRight.y)+ distance ///       |        |
              ) {												  ///       |--------| [other]
        return true;
    } else if ((   topLeft.x     >= otherTopLeft.x	   - distance ///       |---- - - - [this]
                && topLeft.x     <= otherBottomRight.x + distance ///       |
                												  /// |-----|--|
                && topLeft.y	 <= otherTopLeft.y     + distance /// |     |  |
                												  /// |        |
                && bottomRight.y >= otherTopLeft.y)    - distance /// |     |  |
              ) {												  /// |--------| [other]
        return true;
    } else if (   topLeft.x     <= otherTopLeft.x	   + distance /// |------------| 
               && topLeft.y     <= otherTopLeft.y	   + distance /// |   [other]  |
               && bottomRight.x >= otherTopLeft.x	   - distance /// |  |------|  |
               && bottomRight.y >= otherBottomRight.y  - distance /// |  |      |  |
                  												  /// |  |      |  |
                  												  /// |  |------|  |
              ) {												  /// |------------| [this]
        return true;
    } else if (   topLeft.x     >= otherTopLeft.x	   + distance /// |------------| 
               && topLeft.y     >= otherTopLeft.y	   + distance /// |   [this]   |
               && bottomRight.x <= otherTopLeft.x	   - distance /// |  |------|  |
               && bottomRight.y <= otherBottomRight.y  - distance /// |  |      |  |
                  												  /// |  |      |  |
                  												  /// |  |------|  |
              ) {												  /// |------------| [other]
        return true;
    }
	
	return false;
	
}


/**
 * Get the percentile overlap of two rectangles.
 * If the rectangles are of different size, the greater overlap percentage is take as return value
 * //TODO make it more elegant, either by taking the size of the smaller rect as 100%,
 *        or by considering the size of rect 'a' as 100%.
 * 
 * @param a The first rectangle to check
 * @param b The other rectangle to check
 * 
 * @return The percentile overlap p, (0.0 <= p <= 1.0)
 */
double ImageUtils::getOverlap(CvRect a, CvRect b){
	
	double overlap;
	
	
	if (overlaps(a,b)){
		
		CvPoint topLeft, bottomRight, otherTopLeft, otherBottomRight;
		int distance = 0;

		topLeft = cvPoint(a.x, a.y);
		bottomRight = cvPoint(a.x + a.width, a.y + a.height);
		otherTopLeft = cvPoint(b.x, b.y);
		otherBottomRight = cvPoint(b.x + b.width, b.y + b.height);
		
		
		/* first check if one of the rectangles is contained by the other */
		if (   topLeft.x     <= otherTopLeft.x	   + distance /// |------------| 
               && topLeft.y     <= otherTopLeft.y	   + distance /// |   [other]  |
               && bottomRight.x >= otherTopLeft.x	   - distance /// |  |------|  |
               && bottomRight.y >= otherBottomRight.y  - distance /// |  |      |  |
                  												  /// |  |      |  |
                  												  /// |  |------|  |
              ) {												  /// |------------| [this]
        	overlap = 1.0;
	    } else if (   topLeft.x     >= otherTopLeft.x	   + distance /// |------------| 
	               && topLeft.y     >= otherTopLeft.y	   + distance /// |   [this]   |
	               && bottomRight.x <= otherTopLeft.x	   - distance /// |  |------|  |
	               && bottomRight.y <= otherBottomRight.y  - distance /// |  |      |  |
	                  												  /// |  |      |  |
	                  												  /// |  |------|  |
	              ) {												  /// |------------| [other]
	        overlap = 1.0;
	    } else {
	
	    	
	    	/* crude brute force algorithm:
	    	 * Draw one rect in a mask, then count the balck and white pixels in that mask
	    	 * within the bounds of the other rect, then do it vice versa.
	    	 * Calculate the proportions of white pixels to amximum pixel in each rect, then take
	    	 * the maximum value of that as overlap */
	    	/* I know, this could surely be done by simple math. It's rectangles, after all. */
	    	
	    	
			//TODO da gibts bestimmt ne elegantere Moeglichkeit, aber mir fehlt die Zeit, und diese hier passt auch
			
			int blackCountA = 0;
			int whiteCountA = 0;
			int blackCountB = 0;
			int whiteCountB = 0;
			
			//int width  = abs(MathUtils::max(a.x + a.width,  b.x + b.width)  - MathUtils::min(a.x, b.x));
			//int height = abs(MathUtils::max(a.y + a.height, b.y + b.height) - MathUtils::min(a.y, b.y));
			int width=0, height=0;
			(a.x + a.width)>(b.x + b.width) ? width=(a.x+a.width) : width=(b.x+b.width);
			(a.y + a.height)>(b.y + b.height) ? height=(a.y + a.height) : height=(b.y + b.height);
			
			IplImage* mask = cvCreateImage(cvSize(width, height), 8, 1);
			cvZero(mask);
			drawRect(mask, b, cvScalarAll(255), true);
			for (int y = a.y; y < a.y + a.height; ++y){
				for (int x = a.x; x < a.x + a.width; ++x){
					if(getPixelValue(mask, x, y, 0) > 0){
						whiteCountA++;
					} else {
						blackCountA++;
					}
					//setPixelValue(mask, x, y, 0, 0);
				}
			}
			
			cvZero(mask);
			drawRect(mask, a, cvScalarAll(255), true);
			for (int y = b.y; y < b.y + b.height; ++y){
				for (int x = b.x; x < b.x + b.width; ++x){
					if(getPixelValue(mask, x, y, 0) > 0){
						whiteCountB++;
					} else {
						blackCountB++;
					}
					//setPixelValue(mask, x, y, 0, 0);
				}
			}
			 
			cvReleaseImage(&mask); 
			
			double valA=((float)whiteCountA / (float)(whiteCountA + blackCountA));
			double valB=((float)whiteCountB / (float)(whiteCountB + blackCountB));
			valA>valB ? overlap=valA : overlap=valB;
			}
	} else {
		overlap = 0.0;	
	}
	
	return overlap;
}







/**
 * Create a CvRect from two points.
 * 
 * OpenCV only provides a method to create a CvRect by one point and width X height.
 * This is a convenience method to have that done by providing to points, since I find
 * myself to need that quite often (and always writing the below line is just plain annoying).
 * Since CvRect does not specify (nor care) if the coordinates given are the top left corner,
 * a negative width and height are completely acceptable. Thus, no checks are made if (a < b). 
 **/
CvRect ImageUtils::getCvRect(CvPoint a, CvPoint b){
	
	
	return cvRect(a.x, a.y, b.x-a.x, b.y-a.y);
	
}














/**
 * Create a mask from any IplImage (i.e. perform a threshold on it).
 * Needed since OpenCV only supports thresholding on single channel
 * images, while this method also allows creating a mask from color
 * images.
 * The original image will be left unchanged.
 * The mask MUST NOT be null and thus be allocated elsewhere.
 * 
 * @param image The image to perform the threshold on.
 * @param mask The resulting binary image.
 **/
void ImageUtils::createMask(IplImage* image, IplImage* mask){
 	
 	assert(image != NULL);
 	assert(mask != NULL);
 	assert(image->width == mask->width);	
 	assert(image->height == mask->height);
 	assert(mask->nChannels == 1);
 	
 	cvZero(mask);
 	
 	for (int x = 0; x < image->width; ++x){
 		for (int y = 0; y < image->height; ++y){
 			if (getPixelValue(image, x, y) > 0){
 				setPixelValue(mask, x, y, 0, 255);	
 			}		
 		}
 	}	
 	
 }



/**
 * Retrieve a mask from a CvBox2D, i.e. a binary image that contains only the
 * box. 
 * The mask will be allocated by this function, but MUST be released by the
 * calling function.
 * 
 * @param box The box to base the mask on
 * @param width The width of the mask
 * @param height the height of the mask
 * 
 * @return A mask (binary image) containing only the box
 **/
IplImage* ImageUtils::getMaskFromCvBox2D(CvBox2D box, int width, int height){
	
	IplImage* mask = cvCreateImage(cvSize(width, height), 8, 1);
	cvZero(mask);
	
	drawBox2D(mask, box, cvScalarAll(255));
	
	cvFloodFill(mask, cvPointFrom32f(box.center), cvScalarAll(255));
		
	return mask;
}

 



/**
 * Copies the content of one IplImage into another, by the use of a mask.
 * A value of 0 in the mask specifies that a pixel should not be copied, anything
 * else says it should.
 * 
 * @param src The image to copy from
 * @param dst The image to copy to
 * @param mask The mask to copy by
 **/
void ImageUtils::copyByMask(IplImage* src, IplImage* dst, IplImage* mask){
 	assert(src->width == mask->width);	
 	assert(src->height == mask->height);
 	assert(src->width == dst->width);	
 	assert(src->height == dst->height);
 	assert(src->nChannels == dst->nChannels);
 	
 	for (int x = 0; x < src->width; ++x){
 		for (int y = 0; y < src->height; ++y){
 			if (getPixelValue(mask, x, y) > 0){
 				setPixel(dst, getPixel(src, x, y, src->nChannels));	
 			}		
 		}
 	}
 	
}


/**
 * Copy a region from ony IplImage to another.
 * The images must be preallocated, and be of exact same size and depth.
 * Regions will be cropped to fit image boundaries.
 * 
 * @param src The image to copy from
 * @param dst The image to copy to
 * @param start The top left corner of the region
 * @param end The bottom right corner of the region
 **/
void ImageUtils::copyRegion(IplImage* src, IplImage* dst, CvPoint start, CvPoint end) {

	assert(src != NULL);
	assert(dst != NULL);
	assert(src->width == dst->width);
	assert(src->height == dst->height);
	assert(src->nChannels == dst->nChannels);

    CvSize imageSize;

    imageSize = cvGetSize(src);


    /* fit the region to image bounds */
    start.x = start.x >= imageSize.width  ? imageSize.width - 1  : start.x;
    end.x   = end.x   >= imageSize.width  ? imageSize.width - 1  : end.x;
    start.y = start.y >= imageSize.height ? imageSize.height - 1 : start.y;
    end.y   = end.y   >= imageSize.height ? imageSize.height - 1 : end.y;

    
    
    int width;
    int height;
    
    width = (end.x - start.x);
    height = (end.y - start.y);

    for (int y = 0; y <= height; y++) {
        for (int x = 0; x <= width; x++) {
        	for (int channel = 0; channel < src->nChannels; channel++){
        		setPixelValue(dst, x, y, channel, (getPixelValue(src, x, y, channel)));
        	}
        }
    }
}














/**
 * Obtain an resized grayscale image as a flaot array from an input image.
 * 
 * @param image The image to resize
 * @param newWidth The width of the output image
 * @param newHeight The height of the output image
 * 
 * @return A float array representing the input image as grayscale, resized to newWidth x newHeight.
 **/
float** ImageUtils::convertImageToResizedGray( IplImage* image, int newWidth, int newHeight ) {
	
    float ** pixels;
    IplImage *resized = cvCreateImage( cvSize( newWidth, newHeight ), 8, 1 );
    cvZero(resized);
    
    if (image->nChannels != 1){
    	IplImage* greyTmp = cvCreateImage(cvGetSize(image), 8,1);
    	cvZero(greyTmp);
    	
    	cvCvtColor(image, greyTmp, CV_BGR2GRAY);
    	//cvEqualizeHist(greyTmp, greyTmp);
    	cvResize(greyTmp, resized, CV_INTER_CUBIC);
    	
    	cvReleaseImage(&greyTmp);	
    } else {
    	//cvEqualizeHist(image, image);
    	cvResize(image, resized, CV_INTER_CUBIC);
    }
    pixels = convertIplImageToFloat( resized );

    cvReleaseImage( &resized );

    return pixels;
}

/**
 * Convert an IplImage to a float array.
 * 
 * @param image The image to convert.
 * 
 * @return The original image as float#
 **/
float** ImageUtils::convertIplImageToFloat( IplImage *image ) {

    uchar *imageData = ( uchar* )image-> imageData;
    int step = image-> widthStep;
    int w = image->width;
    int h = image->height;

    float **floatImage; //user has to care about deleting!
    floatImage = new float*[ w ];
    for( int i=0; i<w; i++ ) {
    	floatImage[i] = new float[h];
        for( int j=0; j<h; j++ ) {
            float val = (float)((uchar*)( imageData + step*(j)))[i] / 255.0;
            floatImage[i][j] = val;
        }
    }

    return floatImage;
}














/**
 * Retrieve a sub image of an IplImage.
 * Uses less memory than setting the ROI on an IplImage.
 * 
 * @param src The image to obtain a crop from.
 * @param start The top left corner of the sub image.
 * @param end The bottom right corner of the sub image.
 * 
 * @return A cropped version of the original image.
 **/
IplImage* ImageUtils::getSubImage(IplImage* src, CvPoint start, CvPoint end) {
    int newWidth = end.x - start.x;
    int newHeight = end.y - start.y;

    IplImage* subImage = cvCreateImage(cvSize(newWidth, newHeight), src->depth, src->nChannels);
	cvZero(subImage);

    int pixelValue;

    for (int x = 0; x < newWidth; ++x) {
        for (int y = 0; y < newHeight; ++y) {
            for (int channel = 0; channel < src->nChannels; ++channel) {
                pixelValue = getPixelValue(src, x + start.x, y + start.y, channel);
                setPixelValue(subImage, x, y, channel, pixelValue);
            }
        }
    }

    return subImage;

}

/**
 * Retrieve a sub image of an IplImage, as greyscale.
 * Uses less memory than setting the ROI on an IplImage.
 * 
 * @param src The image to obtain a crop from.
 * @param start The top left corner of the sub image.
 * @param end The bottom right corner of the sub image.
 * 
 * @return A greyscale, cropped version of the original image.
 **/
IplImage* ImageUtils::getSubImageAsGray(IplImage* src, CvPoint start, CvPoint end) {
    int newWidth = end.x - start.x;
    int newHeight = end.y - start.y;

    IplImage* subImage = cvCreateImage(cvSize(newWidth, newHeight), src->depth, 1);
	cvZero(subImage);

    float pixelValue;

    for (int x = 0; x < newWidth; ++x) {
        for (int y = 0; y < newHeight; ++y) {

            pixelValue  = (getPixelValue(src, x + start.x, y + start.y, 2)) * 0.114f;
            pixelValue += (getPixelValue(src, x + start.x, y + start.y, 1)) * 0.587f;
            pixelValue += (getPixelValue(src, x + start.x, y + start.y, 0)) * 0.299f;
            setPixelValue(subImage, x, y, 0, (int)ImageUtils::fitRange(pixelValue, 0.0f, 255.0f));

        }
    }

    return subImage;

}

float ImageUtils::fitRange(float value, float low, float high)
{
	if (value < low)
		return low;
	else if (value > high)
		return high;
	return value;
}










 


